import copy

from .const import *
import random
from ai.hexmap.handle_map import *
import numpy as np
from copy import deepcopy


def uv_infer_coord(agent, obj_id, defense_cod):
    """
    王炬江 2022/10/24
    防御位置推理
    :param defense_cod:
    :param agent:
    :param obj_id:
    :return: move_destination
    """
    bop = agent.get_bop(obj_id)  # 无人战车的算子信息
    move_destinations = []  # 记录机动目标的三个点
    if defense_cod:  # 当传入防御点位的时候，防守区域是当前点和它的邻域
        refer_region = copy.deepcopy(agent.map.get_neighbors(defense_cod))
        refer_region.append(defense_cod)
    else:  # 没有传入防御坐标，默认防御是夺控点
        refer_region = []
        for i in agent.city_coord:
            refer_region.append(i)
            single_city_nei = agent.map.get_neighbors(i)  # 某个夺控点出现在其他的夺控点邻域会出现重复数据，可以用list（set（））解决
            refer_region += single_city_nei
    if defense_cod:  # 传入参数时是以参数为中心，没有时以夺控点为中心
        refer_center = defense_cod
    else:
        refer_center = agent.city_center

    # hypotenuse = agent.map.get_distance(bop["cur_hex"], refer_center)
    # if hypotenuse == 0:  # 三角形相似求出18格圆心
    #     return
    # row0, col0 = divmod(bop["cur_hex"], 100)
    # row1, col1 = divmod(refer_center, 100)
    # right_angle_side0 = abs(row0 - row1)
    # right_angle_side1 = abs(col0 - col1)
    # row18_len = int(18 * (right_angle_side0 / hypotenuse)) + 1
    # col18_len = int(18 * (right_angle_side1 / hypotenuse)) + 1
    # if row0 > row1 and col0 > col1:  # 4个象限的坐标调整
    #     move_destination_center = (row1 + row18_len) * 100 + col1 + col18_len
    # elif row0 > row1 and col0 < col1:
    #     move_destination_center = (row1 + row18_len) * 100 + col1 - col18_len
    # elif row0 < row1 and col0 < col1:
    #     move_destination_center = (row1 - row18_len) * 100 + col1 - col18_len
    # else:
    #     move_destination_center = (row1 - row18_len) * 100 + col1 + col18_len
    # move_destination_center 可能是无效点超过地图的点
    move_destination_region0 = agent.map.get_grid_distance(bop["cur_hex"], 0, 10)  # 最原始的点区域
    if defense_cod:  # 筛选掉距离防守点距离5以内的点
        move_destination_region_not = agent.map.get_grid_distance(defense_cod, 0, 5)
    else:
        move_destination_region_not = agent.get_distance_coord(5)
    move_destination_region1 = agent.map.get_grid_distance(refer_center, 0, 25)  # 保证在夺控点距离25以内
    move_destination_region0 = move_destination_region0.intersection(move_destination_region1)
    move_destination_region_not0 = move_destination_region0.intersection(move_destination_region_not)
    move_destination_region = move_destination_region0 - move_destination_region_not0  # 筛选出来的所有点
    move_destination_in_cover_region = agent.map.get_grid_in_cover(move_destination_region)  # 筛选出的掩蔽点
    in_cover_region_see_sum = []
    in_cover_average_region = []  # 记录可以通视的所有点
    in_cover_average0 = []  # 对应的通视数量的记录
    in_cover_average = []  # 加权平均，即最后筛选的标准
    # 10半径没有掩蔽地形是在区域中考虑没有掩蔽地形的点还是继续扩大半径找
    if bool(move_destination_in_cover_region) is False:
        for i in range(11, 15):
            move_destination_region0 = agent.map.get_grid_distance(bop["cur_hex"], i, i)
            move_destination_region0 = move_destination_region0.intersection(move_destination_region1)
            move_destination_region_not1 = move_destination_region0.intersection(move_destination_region_not)
            move_destination_region = move_destination_region0 - move_destination_region_not1
            move_destination_in_cover_region = agent.map.get_grid_in_cover(move_destination_region)
            if move_destination_in_cover_region:
                break
        if not move_destination_in_cover_region:  # 14区域还是空的就不机动
            return
    for i in move_destination_in_cover_region:  # 以车辆通视为依据
        num = see_sum(agent, i, refer_region, obj_id)
        if num > 0:
            in_cover_average_region.append(i)
            in_cover_average0.append(num)
        # in_cover_region_see_sum.append(num)
    # max_see_num0 = max(in_cover_region_see_sum)
    if in_cover_average_region:
        max_see = max(in_cover_average0)  # 对通视的数量进行归一化
        in_cover_average0 = [i / max_see for i in in_cover_average0]
        in_cover_average1 = [agent.map.get_distance(i, bop["cur_hex"]) for i in in_cover_average_region]
        max_distance0 = max(in_cover_average1)  # 对距离当前的坐标距离归一化
        in_cover_average1 = [i / max_distance0 for i in in_cover_average1]
        in_cover_average2 = [agent.map.get_distance(i, agent.city_center) for i in in_cover_average_region]
        max_distance1 = max(in_cover_average2)  # 对距离夺控点的距离进行归一化
        in_cover_average2 = [i / max_distance1 for i in in_cover_average2]
        in_cover_average = [in_cover_average0[i] * 0.8 + in_cover_average1[i] * (-0.1) + in_cover_average2[i] * 0.1
                            for i in range(len(in_cover_average0))]  # 加权平均，即最后筛选的标准
    if not in_cover_average_region:  # 有掩蔽地形但是没有可以通视的点的情况
        distance_list = [agent.map.get_distance(i, agent.city_coord[0]) for i in
                         move_destination_in_cover_region]  # 坐标与夺控点的距离列表
        b = distance_list.index(min(distance_list))
        # 邻域距离坐标中的最小值的索引
        move_destination = list(move_destination_in_cover_region)[b]
        return move_destination  # 移动到这里后是看不到观察区域的还得继续机动到其他地方,到这里的堆叠还没考虑
    else:  # 依次取出加权平均最大的三个点（取第一个最大的后，令对应位置为0，再取第二大的值。需要注意变量的对应和索引的对应）
        # 在半径11-14时候的点可能取不到3个通视的
        max_see_average0 = max(in_cover_average)
        index0 = in_cover_average.index(max_see_average0)
        in_cover_average[index0] = 0
        move_destination0 = in_cover_average_region[index0]
        move_destinations.append(move_destination0)
        max_see_average1 = max(in_cover_average)
        index1 = in_cover_average.index(max_see_average1)
        in_cover_average[index1] = 0
        move_destination1 = in_cover_average_region[index1]
        move_destinations.append(move_destination1)
        max_see_average2 = max(in_cover_average)
        index2 = in_cover_average.index(max_see_average2)
        move_destination2 = in_cover_average_region[index2]
        move_destinations.append(move_destination2)
        move_destination = random.choice(move_destinations)  # 采用随机，即等可能输出
        if move_destination:
            return move_destination


def see_sum(agent, single, region, obj_id):  # "一个点对一个区域按照bop通视的数量"
    bop = agent.get_bop(obj_id)
    tmp_bop0 = deepcopy(bop)  # 深拷贝防止数据的更改
    tmp_bop1 = deepcopy(bop)
    tmp_bop0['cur_hex'] = single
    num = 0
    for i in region:
        tmp_bop1['cur_hex'] = i
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
    return num


def change_ugv_pos(agent, obj_id):
    """
    毕珊宁 2022-10-24
    为避免无人战车遭受可能的伤害，变更当前位置
    :param agent:
    :param obj_id:
    :return ：坐标 tar_hex
    """
    bop = agent.get_bop(obj_id)
    neighbors = list(agent.map.get_grid_distance(bop['cur_hex'], 1, 3))
    tar_hex_list = []
    for jm_point in agent.observation['jm_points']:  # 遍历间瞄点信息
        for neighbor in neighbors:
            if jm_point['pos'] == neighbor:
                neighbors.remove(neighbor)
                continue
    for neighbor in neighbors:
        if agent.map.get_grid_type(neighbor) == 1 or agent.map.get_grid_type(neighbor) == 2:  # 如果周围有从林地或居民地
            tar_hex_list.append(neighbor)
    if tar_hex_list:
        map_distance_list = [agent.map.get_distance(i, bop['cur_hex']) for i in tar_hex_list]  # 邻域坐标与夺控点坐标的距离列表
        b = map_distance_list.index(min(map_distance_list))  # 邻域距离坐标中的最小值的索引
        tar_hex = tar_hex_list[b]
    else:
        distances = [agent.map.get_distance(i, bop['cur_hex']) for i in neighbors]
        ind = distances.index(min(distances))
        tar_hex = neighbors[ind]
    return tar_hex


def CruiseMissle_patrol(agent, CruiseMissle_region, cur_hex):
    """
    王炬江 2022/10/28
    巡飞弹巡逻位置推理
    :param agent:
    :param CruiseMissle_region:
    :param cur_hex:
    :return: best_pos
    """
    best_pos = cur_hex  # 最后输出的点
    best_poss = []  # 效能前3的点
    radius_regions = []  # 当前点半径依次扩大的点，为了索引对应
    radius_regions_efficiencies = []  # radius_regions的效能
    efficiencies_amend0 = []  # 距离当前位置的效能修正
    efficiencies_amend = []  # 根据距离当前位置和夺控点距离的修正
    efficiencies_poss = []  # 效能前3点的效能
    if cur_hex in CruiseMissle_region:
        for radius in range(1, 11):
            radius_region = list(agent.map.get_grid_distance(cur_hex, radius, radius))
            radius_regions += radius_region
            radius_region_efficiencies = [agent.observation["time"]["cur_step"] - agent.situation.visual_field[j][0]
                                          if j in CruiseMissle_region else -1 for j in radius_region]
            radius_regions_efficiencies += radius_region_efficiencies
            # 有的邻域点没有在作战区域会没有效能
            efficiencies_amend0 += [j * pow(0.85, radius) for j in radius_region_efficiencies]
        efficiencies_amend1 = [pow(0.7, agent.map.get_distance(cur_hex, j)) for j in radius_regions]
        efficiencies_amend = [efficiencies_amend0[i] * efficiencies_amend1[i] for i in range(len(efficiencies_amend0))]
        index0 = efficiencies_amend.index(max(efficiencies_amend))
        efficiencies_poss.append(efficiencies_amend[index0])  # 取效能前3的坐标和效能修正
        efficiencies_amend[index0] = -1
        best_poss.append(radius_regions[index0])
        index1 = efficiencies_amend.index(max(efficiencies_amend))
        efficiencies_poss.append(efficiencies_amend[index1])
        efficiencies_amend[index1] = -1
        best_poss.append(radius_regions[index1])
        index2 = efficiencies_amend.index(max(efficiencies_amend))
        efficiencies_poss.append(efficiencies_amend[index2])
        efficiencies_amend[index2] = -1
        best_poss.append(radius_regions[index2])
        efficiencies_softmax = softmax(efficiencies_poss)
        a = random.random()
        if a <= efficiencies_softmax[0]:
            best_pos = best_poss[0]
        elif efficiencies_softmax[0] < a <= (efficiencies_softmax[0] + efficiencies_softmax[1]):
            best_pos = best_poss[1]
        else:
            best_pos = best_poss[2]
        return best_pos
    else:
        row_list = []
        col_list = []
        for i in agent.situation.refer_city_changes:
            row_city, col_city = divmod(i, 100)
            row_list.append(row_city)  # 行
            col_list.append(col_city)  # 列
        row_min = min(row_list)
        col_min = min(col_list)
        row_max = max(row_list)
        col_max = max(col_list)
        city_changes_center = (row_min + int(0.5 * (row_max - row_min))) * 100 + \
                              (col_min + int(0.5 * (col_max - col_min)))
        route, _ = agent.map.gen_move_route(cur_hex, city_changes_center, 3)
        for i in route:
            if i in list(CruiseMissle_region):
                best_pos = i
                break
        return best_pos


def softmax(x):  # softmax函数完成概率的选值
    row_max = np.max(x)
    x = x - row_max
    x_exp = np.exp(x)
    x_sum = np.sum(x_exp)
    s = x_exp / x_sum
    return s


def CruiseMissle_enemy_choice(agent, obj_id, cur_hex):
    """
    王炬江 2022/10/30
    巡飞弹确定射击目标
    :param agent:
    :param obj_id:
    :param cur_hex:
    :return: enemy['cur_hex']
    """
    bop = agent.get_bop(obj_id)
    # 需要一个对应的situation属性有算子的类型，血量，上一次坐标
    remain_time = bop["alive_remain_time"]
    if remain_time >= 80:
        radius = int((remain_time - 25) / 8) + 1  # 冗余时间为17——25秒
    elif 80 > remain_time > 26:
        radius = int(remain_time / 8) + 1
    else:
        radius = 3
    enemy_list = []  # 记录巡飞弹可以射击到的所有敌人算子
    operators_info = list(agent.situation.enemy.values())
    for i in operators_info:
        if agent.map.get_distance(i["coord"], cur_hex) < radius:
            enemy_list.append(i)
    Infantry_list = [j for j in enemy_list if j["sub_type"] == 2 and
                     (agent.observation["time"]["cur_step"] - j["last_step"]) < 50]
    IFV_list = [j for j in enemy_list if j["sub_type"] == 1 and
                (agent.observation["time"]["cur_step"] - j["last_step"]) < 9]
    tanks = [j for j in enemy_list if j["sub_type"] == 0 and
             (agent.observation["time"]["cur_step"] - j["last_step"]) < 9]
    UGV_list = [j for j in enemy_list if j["sub_type"] == 4 and
                (agent.observation["time"]["cur_step"] - j["last_step"]) < 9]
    if Infantry_list:
        best = min(Infantry_list, key=lambda x: x["cur_blood"])
        return best["coord"], best["obj_id"]
    elif tanks:
        best = min(tanks, key=lambda x: x["cur_blood"])
        return best["coord"], best["obj_id"]
    elif IFV_list:
        best = min(IFV_list, key=lambda x: x["cur_blood"])
        return best["coord"], best["obj_id"]
    elif UGV_list:
        best = min(UGV_list, key=lambda x: x["cur_blood"])
        return best["coord"], best["obj_id"]
    else:
        return None, None


def judge_guide_shoot(agent, obj_id):
    """
    毕珊宁 2022-11-6
    判断能否见瞄校射，如果能输出推理的见瞄校射位置，不能输出false
    :param agent:
    :param obj_id:
    :return: tar_hex False
    """
    # 是否在间瞄校射流程中：

    # 如果不在流程中
    # 先记录历史的校射目标点
    land_location = []  # 我方地面算子坐标
    drone_location = []
    pos = []
    trash = []
    bop = agent.get_bop(obj_id)
    for operator0 in agent.observation['operators']:
        if operator0['color'] == agent.color and operator0['type'] != 3:  # 我方地面算子
            land_location.append(operator0['cur_hex'])  # 记录我方地面算子坐标
    if bop['sub_type'] == 5:  # 如果为无人机
        for operator in agent.observation['operators']:
            if operator['color'] == agent.color:  # 取出我方无人机位置
                if operator['sub_type'] == 5:  # 5 无人机
                    drone_location.append(operator['cur_hex'])
        if judge_jmplan_over(agent, obj_id) == True:  # 如果不在见瞄校射流程中：
            if agent.observation['jm_points']:
                standby1 = agent.observation['jm_points']
                for jmpoint in agent.observation['jm_points']:  # 遍历见瞄点信息
                    if jmpoint['color'] == agent.color and jmpoint['status'] == 0:  # 我方正在飞行的
                        # 下面判断是不是新的
                        if operator[
                            'obj_id'] not in agent.judge_jmpoints_historical_positions.keys():  # 11/21/1240 yd 增加id是否存在与字典内的判断
                            for land_local in land_location:
                                if agent.map.can_see(land_local, jmpoint['pos'], 0):  # 判断地面算子是否如见瞄点通识
                                    trash.append(jmpoint)
                            # if not self.map.can_see(bop['cur_hex'], jmpoint['pos'], 0):  # 地面算子与见瞄点通识
                            distance = agent.map.get_distance(bop['cur_hex'], jmpoint['pos'])  # 无人机和弹着点距离
                            a, b = divmod(distance, 3)
                            move_time = a * 25 + 8 * b
                            if 450 - jmpoint['fly_time'] > move_time or 300 - jmpoint[
                                'boom_time'] > move_time:  # 11/21/1259 yd 无人机可以在爆炸前到达：
                                if bop['cur_hex'] in drone_location:  #
                                    drone_location.remove(bop['cur_hex'])
                                    for dronelocal in drone_location:
                                        distance_new = agent.map.get_distance(jmpoint['pos'], dronelocal)  # 其他无人机与弹着点距离
                                        # 此处缺少一个 其他无人机是否是空闲的判断
                                        if distance_new < distance:
                                            trash.append(jmpoint)
                            else:
                                trash.append(jmpoint)  # trash列表用来存放所有不和要求的见瞄点
                        elif jmpoint['pos'] != agent.judge_jmpoints_historical_positions[obj_id][
                            1]:  # 判断这个点有没有被推测过 ----有问题----
                            for land_local in land_location:
                                if agent.map.can_see(land_local, jmpoint['pos'], 0):  # 判断地面算子是否如见瞄点通识
                                    trash.append(jmpoint)
                            # if not self.map.can_see(bop['cur_hex'], jmpoint['pos'], 0):  # 地面算子与见瞄点通识
                            distance = agent.map.get_distance(bop['cur_hex'], jmpoint['pos'])  # 无人机和弹着点距离
                            a, b = divmod(distance, 3)
                            move_time = a * 25 + 8 * b
                            if jmpoint['status'] == 0 and 450 - jmpoint['fly_time'] > move_time or jmpoint[
                                'status'] == 1 and 300 - jmpoint['boom_time'] > move_time:  # 11/21/1259 yd 无人机可以在爆炸前到达：
                                if bop['cur_hex'] in drone_location:
                                    drone_location.remove(bop['cur_hex'])
                                    for dronelocal in drone_location:
                                        distance_new = agent.map.get_distance(jmpoint['pos'], dronelocal)  # 其他无人机与弹着点距离
                                        # 此处缺少一个 其他无人机是否是空闲的判断
                                        if distance_new < distance:
                                            trash.append(jmpoint)
                            else:
                                trash.append(jmpoint)  # trash列表用来存放所有不和要求的见瞄点
                if trash:
                    for i in trash:
                        if i in standby1:
                            standby1.remove(i)  # 在所有的见瞄点中删除不和规定的见瞄点
                if standby1:
                    for jilu_jmpoint in standby1:
                        pos.append(jilu_jmpoint['pos'])  # 取出见瞄点信息中的位置坐标
                    pos0 = random.choice(pos)  # 随机选择一个位置坐标
                    # jmpoint1 = random.choice(jilu_jmpoints['pos'])
                    # 推理位置
                    hex_list = list(agent.map.get_grid_distance(pos0, 1, 2))  # 距离弹着点距离为2圆环内的坐标
                    if hex_list:
                        distance_list = [agent.map.get_distance(i, bop['cur_hex']) for i in
                                         hex_list]  # 邻域坐标与夺控点坐标的距离列表
                        b = distance_list.index(min(distance_list))  # 邻域距离坐标中的最小值的索引
                        tar_hex = hex_list[b]
                        agent.judge_jmpoints_historical_positions[obj_id][0] = \
                            agent.observation['time']['cur_step']
                        agent.judge_jmpoints_historical_positions[obj_id][1] = tar_hex
                        agent.jmpoints_historical_positions[obj_id][0] = \
                            agent.observation['time']['cur_step']
                        agent.jmpoints_historical_positions[obj_id][1] = pos0

                        return tar_hex
                else:
                    return False
            else:
                return False
        else:
            return judge_jmplan_over(agent, obj_id)


def judge_jmplan_over(agent, obj_id):
    """
    判断见瞄校射是否结束
    :return: False tar_hex
    """
    bop = agent.get_bop(obj_id)
    if bop['sub_type'] == 5:  # 如果为无人机
        if agent.observation['jm_points']:
            for jm_point in agent.observation['jm_points']:
                if jm_point['color'] == agent.color and (
                        jm_point['status'] == 1 or jm_point['status'] == 0):  # 11/21/1340 增加正在飞行的判断 如果是 判断爆炸 ?
                    if agent.jmpoints_historical_positions[obj_id][1]:
                        if jm_point['boom_time'] != 300:  # 11/21/1341 爆炸没结束 0 to 300
                            if obj_id == agent.cancel_jmplan[obj_id]:  # 见瞄计划取消
                                if agent.cancel_jmplan[obj_id][0]:
                                    return True
                            tar_hex = agent.judge_jmpoints_historical_positions[obj_id][1]  # 输出上次的推理点
                            # 判断爆炸完了吗 炸完了清空
                            for jm_point0 in agent.observation['jm_points']:
                                if jm_point0['color'] == agent.color and jm_point0['pos'] == \
                                        agent.jmpoints_historical_positions[obj_id][1]:
                                    if jm_point0['boom_time'] == 300:
                                        agent.judge_jmpoints_historical_positions.pop(obj_id)
                                        agent.jmpoints_historical_positions.pop(obj_id)
                                    return tar_hex
                        else:  # 如果结束了
                            return True
                    else:  # 没有说明取消见瞄了
                        print("无在历史间瞄点")
                        return True
                else:  # 不在流程中 接判断 judge—jm***
                    print("无在飞行/爆炸的我方间瞄点")
                    return True
        print("无间瞄点")
        return True


def judge_infer_guide_shoot(agent, obj_id):
    """
    吴欣娟 2022/11/18
    判断是否能引导射击，不能输出false,能就推理适合引导射击的位置并输出
    return: False destination
    """
    enemies_operators = []
    enemies = []
    target_enemy = None
    destination = None
    ifv = []
    ifv_id = []
    target_obj_id = []
    standby = []
    bop = agent.get_bop(obj_id)
    if bop['sub_type'] == BopSubType.Drone:  # 确保算子是无人机
        if judge_jmplan_over(agent, obj_id):
            if bop["guide_ability"]:  # 确保算子有引导射击能力
                scope = list(agent.map.get_grid_distance(bop['cur_hex'], 0, 17))  # 以无人机为中心取一个半径为17的圆
                operators = agent.observation['operators'] + agent.observation["passengers"]
                for operator in operators:  # 遍历所有能看到的敌方算子
                    if operator['color'] != agent.color:
                        enemies_operators.append(operator)
                if enemies_operators:
                    for enemy in enemies_operators:  # 确保算子已经停止且不在掩蔽地形中
                        if (enemy['cur_hex'] in scope) and (enemy['sub_type'] == BopSubType.UGV or enemy[
                            'sub_type'] == BopSubType.IFV):  # 确保敌方算子在范围内且为战车
                            if enemy['obj_id'] in agent.situation.enemies.keys():
                                enemy_obj_id = enemy['obj_id']
                                if enemy['cur_hex'] in agent.situation.enemies[enemy_obj_id][
                                    'historical_positions'].keys():
                                    cur_hex = enemy['cur_hex']
                                    historical_positions = \
                                        agent.situation.enemies[enemy_obj_id]['historical_positions'][
                                            enemy['cur_hex']]
                                    if agent.observation['time']['cur_step'] - historical_positions[1] < 2:
                                        if agent.observation['time']['cur_step'] - historical_positions[0] > 75:
                                            if (agent.map_data[cur_hex // 100][cur_hex % 100]['cond']) != 1 and (
                                                    agent.map_data[cur_hex // 100][cur_hex % 100]['cond']) != 2:
                                                enemies.append(enemy)
                if enemies:
                    for operator in operators:  # 取出我方所有重型战车算子
                        if operator['color'] == agent.color and operator['sub_type'] == BopSubType.IFV:
                            if operator["remain_bullet_nums"][100] > 0:
                                ifv.append(operator)
                    for enemy in enemies:  # 确保敌方算子在我方重型战车的射程中
                        record = 0
                        for one in ifv:
                            if agent.map.get_distance(enemy['cur_hex'], one['cur_hex']) < 21:
                                ifv_id.append(one['obj_id'])
                                record += 1
                            else:
                                pass
                        if record == 0:
                            standby.append(enemy)  # 存放不符合要求的敌方算子
                    for enemy in enemies:
                        record = 0
                        for operator in operators:
                            if operator['sub_type'] == BopSubType.UGV:
                                if agent.map.can_see(operator['cur_hex'], enemy['cur_hex'], 0):  # 确保算子不能被我方无人战车引导射击
                                    if operator['car'] and operator['car'] in ifv_id:
                                        record += 1
                                    else:
                                        if operator['launcher'] and operator['launcher'] in ifv_id:
                                            record += 1
                            elif operator['sub_type'] == BopSubType.Infantry:
                                if agent.map.can_see(operator['cur_hex'], enemy['cur_hex'], 0):  # 确保算子不能被我方步兵引导射击
                                    if operator['car'] and operator['car'] in ifv_id:
                                        record += 1
                                    else:
                                        if operator['launcher'] and operator['launcher'] in ifv_id:
                                            record += 1
                            elif operator['sub_type'] == BopSubType.Drone:  # 确保算子不能被我方其它无人机引导射击
                                if operator['obj_id'] != bop['obj_id'] and agent.map.get_distance(operator['cur_hex'],
                                                                                                  enemy['cur_hex']) < 3:
                                    standby.append(enemy)
                                    continue
                            else:
                                continue
                        if record == 0:
                            standby.append(enemy)
                    for valid_actions in agent.observation["valid_actions"].values():  # 确保算子不是我方其它算子的射击/引导射击目标
                        if valid_actions:
                            if ActionType.Shoot in valid_actions.keys():
                                for action in valid_actions[ActionType.Shoot]:
                                    target_obj_id.append(action["target_obj_id"])
                            elif ActionType.GuideShoot in valid_actions.keys():
                                for action in valid_actions[ActionType.GuideShoot]:
                                    target_obj_id.append(action["target_obj_id"])
                            else:
                                continue
                    for enemy in enemies:
                        if enemy['obj_id'] in target_obj_id:
                            standby.append(enemy)
                    for obj_id, target in agent.drone_guide.items():  # 确保算子不能被我方无人机引导射击
                        for enemy in enemies:
                            if obj_id != bop['obj_id'] and target == enemy['obj_id']:
                                standby.append(enemy)
                    if standby:  # 删除不符合要求的算子
                        for i in standby:
                            if i in enemies:
                                enemies.remove(i)
                        standby.clear()
                if enemies:  # 选择距离最近的敌方算子
                    distances = [agent.map.get_distance(enemy['cur_hex'], bop['cur_hex']) for enemy in enemies]
                    index = distances.index(min(distances))
                    target_enemy = enemies[index]
                if target_enemy:  # 根据选定的敌方算子，推理引导射击位置：距离敌方算子2格、不可被其它敌方算子观察、距离更近
                    target_pos = list(agent.map.get_grid_distance(target_enemy['cur_hex'], 2, 2))
                    if target_pos:
                        for enemy in enemies_operators:
                            for point in target_pos:
                                if agent.map.get_distance(point, enemy['cur_hex']) < 2:
                                    standby.append(point)
                        if standby:
                            for i in standby:
                                if i in target_pos:
                                    target_pos.remove(i)
                            standby.clear()
                    if target_pos:
                        distances = [agent.map.get_distance(point, bop['cur_hex']) for point in target_pos]
                        index = distances.index(min(distances))
                        destination = target_pos[index]
                if destination:
                    if bop['obj_id'] in agent.drone_infer.keys():
                        if agent.drone_infer[bop['obj_id']][1] == destination:
                            agent.drone_infer[bop['obj_id']][0] = agent.observation['time']['cur_step']
                        else:
                            agent.drone_infer[bop['obj_id']] = [agent.observation['time']['cur_step'], destination]
                    return destination
    return False


def UAV_patrol(agent, CruiseMissle_region, cur_hex):
    """
    王炬江 2022/11/19
    无人机巡逻位置推理
    :param agent:
    :param CruiseMissle_region:
    :param cur_hex:
    :return: best_pos
    """
    Infantrys_coords = set()  # 步兵和步兵的邻域坐标的集合
    for i in agent.situation.enemy.items():
        i_1 = i[1]
        if i_1["sub_type"] == 2:
            Infantrys_coords.add(i_1["coord"])
            nei_coord = set(agent.map.get_neighbors(i_1["coord"]))
            Infantrys_coords = Infantrys_coords.union(nei_coord)
    patrol_region = CruiseMissle_region - Infantrys_coords  # 主战场区域减去步兵可以射击的区域
    best_pos = CruiseMissle_patrol(agent, patrol_region, cur_hex)
    return best_pos


def infantry_attack_infer_coord(agent, obj_id, defense_cod):
    """
    袁铎
    :param defense_cod:
    :param agent:
    :param obj_id:
    :return: move_destination
    """
    # 没考虑为空的情况
    # TODO：最后的交集可能会出现为空的情况（临时措施：如果最后的交集为空则选择距离夺控点周围6个点中靠近当前点位的一个点）
    bop = agent.get_bop(obj_id)  # 重型战车的算子信息
    if defense_cod:  # 当传入防御点位的时候，防守区域是当前点和它的邻域
        refer_region = agent.map.get_neighbors(defense_cod)
        refer_region.append(defense_cod)
        refer_defence_pos = defense_cod
    else:  # 没有传入防御坐标，默认防御是夺控点
        refer_region = []  # 目标夺控点以及周围点位的点集
        distance = 65535
        for i in agent.city_coord:
            xx = True
            if agent.map.get_distance(bop['cur_hex'], i) < distance:  # 选取最近的不是其他步兵防御的夺控点作为目标防御点
                if agent.infantrt_defend_city:
                    if i in agent.infantrt_defend_city.values():
                        xx = False;
                if xx == True:
                    distance = agent.map.get_distance(bop['cur_hex'], i)
                    refer_defence_pos = i  # 目标夺控点
        refer_region.append(refer_defence_pos)
        single_city_nei = agent.map.get_neighbors(refer_defence_pos)  # 某个夺控点出现在其他的夺控点邻域会出现重复数据，可以用list（set（））解决
        refer_region += single_city_nei

    direction = get_direction(refer_defence_pos, bop['cur_hex'])
    direction_down = (direction + 1) % 6  #
    direction_up = (direction - 1) % 6

    # get_sector(refer_defence_pos,)

    in_cover_region = agent.map.get_grid_distance(refer_defence_pos, 5, 10)
    in_cover_region = agent.map.get_grid_in_cover(in_cover_region)
    can_see_and_in_cover_5_10_region = []
    for i in in_cover_region:
        if agent.map.can_see(refer_defence_pos, i, 0):
            can_see_and_in_cover_5_10_region.append(i)
    _10_25_region = agent.map.get_grid_distance(refer_defence_pos, 10, 25)
    can_see_region = []  # 保存10-25之间能够通视的点位
    for i in _10_25_region:
        if agent.map.can_see(refer_defence_pos, i, 0):
            can_see_region.append(i)
    can_see_region_set = set(can_see_region)
    can_see_and_in_cover_5_10_region_set = set(can_see_and_in_cover_5_10_region)
    denfend_region_choice = can_see_region_set | can_see_and_in_cover_5_10_region_set  # 步兵目标点位候选点集

    vichles_region = agent.map.get_grid_distance(bop["cur_hex"], 0, distance)  # 初始位置distance格以内的圆作为候选点
    vichles_region = can_not_see_sum(agent, refer_defence_pos, vichles_region)  # 与目标点不通视的坐标
    road_can_see_region = []
    for i in vichles_region:
        if agent.map.get_road_type(i) != 0:
            road_can_see_region.append(i)  # 有道路且不通视的坐标
    tacke_cover_road_can_see_region = agent.map.get_grid_in_cover(road_can_see_region)  # 有掩蔽地形且有道路且不通视的坐标
    tacke_cover_road_can_see_region_set = set(tacke_cover_road_can_see_region)  # 转化为集合
    tacke_cover_road_can_see_region_set_ = set()  # 将战车可选位置扩大2格
    for i in tacke_cover_road_can_see_region_set:
        tacke_cover_road_can_see_region_set_ = tacke_cover_road_can_see_region_set_ | set(
            agent.map.get_grid_distance(i, 0, 2))  # 将战车可选位置扩大2格

    denfend_region_choice_set = set(denfend_region_choice)
    final_choice = denfend_region_choice_set & tacke_cover_road_can_see_region_set_  # 最后的交集
    if len(final_choice) == 0:
        final_choice.update(agent.map.get_neighbors(refer_defence_pos))
        distance = 65535
        final = 0
        for i in final_choice:
            if agent.map.get_distance(bop['cur_hex'], i) < distance:
                final = i
        final_choice = set([i])

    max_can_see_num = 0
    max_init_destance = 0
    max_target_destance = 0
    can_see_num_list = []
    init_destance_list = []
    target_destance_list = []
    for i in final_choice:
        can_see_num = 0
        init_destance = 0
        target_destance = 0
        for j in single_city_nei:
            if agent.map.can_see(i, j, 0):
                can_see_num += 1
        init_destance = agent.map.get_distance(i, bop['cur_hex'])
        target_destance = agent.map.get_distance(i, refer_defence_pos)
        if can_see_num > max_can_see_num:
            max_can_see_num = can_see_num
        if init_destance > max_init_destance:
            max_init_destance = init_destance
        if target_destance > max_target_destance:
            max_target_destance = target_destance
        can_see_num_list.append(can_see_num)
        init_destance_list.append(init_destance)
        target_destance_list.append(target_destance)
    weight_list = [0] * len(final_choice)
    for i in range(0, len(final_choice) - 1):
        weight_list[i] += can_see_num_list[i] / max_can_see_num
        weight_list[i] -= init_destance_list[i] / max_init_destance
        weight_list[i] += target_destance_list[i] / max_target_destance
    final_choice_ = list(final_choice)
    infantry_tar_pos = final_choice_[weight_list.index(max(weight_list))]
    min = 65535
    Vehicles_tar_pos = None
    for i in tacke_cover_road_can_see_region:
        if min > agent.map.get_distance(infantry_tar_pos, i):
            min = agent.map.get_distance(infantry_tar_pos, i)
            Vehicles_tar_pos = i
    if infantry_tar_pos:
        return refer_defence_pos, infantry_tar_pos, Vehicles_tar_pos
    else:
        return refer_defence_pos,refer_defence_pos,refer_defence_pos


def infantry_attack_infer_coord_without_car(agent, obj_id, defense_cod):
    """
    此函数用于对应在下车之后重新推理函数的情况
    袁铎
    :param defense_cod:
    :param agent:
    :param obj_id:
    :return: move_destination
    """
    # 没考虑为空的情况
    # TODO：最后的交集可能会出现为空的情况（临时措施：如果最后的交集为空则选择距离夺控点周围6个点中靠近当前点位的一个点）
    bop = agent.get_bop(obj_id)  # 重型战车的算子信息
    if defense_cod:  # 当传入防御点位的时候，防守区域是当前点和它的邻域
        refer_region = agent.map.get_neighbors(defense_cod)
        refer_region.append(defense_cod)
        refer_defence_pos = defense_cod
    else:  # 没有传入防御坐标，默认防御是夺控点
        refer_region = []  # 目标夺控点以及周围点位的点集
        distance = 65535
        for i in agent.city_coord:
            xx = True
            if agent.map.get_distance(bop['cur_hex'], i) < distance:  # 选取最近的不是其他步兵防御的夺控点作为目标防御点
                if agent.infantrt_defend_city:
                    if i in agent.infantrt_defend_city.values():
                        xx = False;
                if xx == True:
                    distance = agent.map.get_distance(bop['cur_hex'], i)
                    refer_defence_pos = i  # 目标夺控点
        refer_region.append(refer_defence_pos)
        single_city_nei = agent.map.get_neighbors(refer_defence_pos)  # 某个夺控点出现在其他的夺控点邻域会出现重复数据，可以用list（set（））解决
        refer_region += single_city_nei

    direction = get_direction(refer_defence_pos, bop['cur_hex'])
    direction_down = (direction + 1) % 6  #
    direction_up = (direction - 1) % 6

    # get_sector(refer_defence_pos,)

    in_cover_region = agent.map.get_grid_distance(refer_defence_pos, 5, 10)
    in_cover_region = agent.map.get_grid_in_cover(in_cover_region)
    can_see_and_in_cover_5_10_region = []
    for i in in_cover_region:
        if agent.map.can_see(refer_defence_pos, i, 0):
            can_see_and_in_cover_5_10_region.append(i)
    _10_25_region = agent.map.get_grid_distance(refer_defence_pos, 10, 25)
    can_see_region = []  # 保存10-25之间能够通视的点位
    for i in _10_25_region:
        if agent.map.can_see(refer_defence_pos, i, 0):
            can_see_region.append(i)
    can_see_region_set = set(can_see_region)
    can_see_and_in_cover_5_10_region_set = set(can_see_and_in_cover_5_10_region)
    denfend_region_choice = can_see_region_set | can_see_and_in_cover_5_10_region_set  # 步兵目标点位候选点集
    denfend_region_choice_set = set(denfend_region_choice)

    final_choice = denfend_region_choice_set  # 最后的交集
    if len(final_choice) == 0:
        final_choice.update(agent.map.get_neighbors(refer_defence_pos))
        distance = 65535
        final = 0
        for i in final_choice:
            if agent.map.get_distance(bop['cur_hex'], i) < distance:
                final = i
        final_choice = set([i])

    max_can_see_num = 0
    max_init_destance = 0
    max_target_destance = 0
    can_see_num_list = []
    init_destance_list = []
    target_destance_list = []
    for i in final_choice:
        can_see_num = 0
        init_destance = 0
        target_destance = 0
        for j in single_city_nei:
            if agent.map.can_see(i, j, 0):
                can_see_num += 1
        init_destance = agent.map.get_distance(i, bop['cur_hex'])
        target_destance = agent.map.get_distance(i, refer_defence_pos)
        if can_see_num > max_can_see_num:
            max_can_see_num = can_see_num
        if init_destance > max_init_destance:
            max_init_destance = init_destance
        if target_destance > max_target_destance:
            max_target_destance = target_destance
        can_see_num_list.append(can_see_num)
        init_destance_list.append(init_destance)
        target_destance_list.append(target_destance)
    weight_list = [0] * len(final_choice)
    for i in range(0, len(final_choice) - 1):
        weight_list[i] += can_see_num_list[i] / max_can_see_num
        weight_list[i] -= init_destance_list[i] / max_init_destance
        weight_list[i] += target_destance_list[i] / max_target_destance
    final_choice_ = list(final_choice)
    infantry_tar_pos = final_choice_[weight_list.index(max(weight_list))]
    min = 65535
    Vehicles_tar_pos = None
    if infantry_tar_pos:
        return refer_defence_pos, infantry_tar_pos
    else:
        return refer_defence_pos,refer_defence_pos


def can_not_see_sum(agent, single_pos, region):  # 一个区域内对一个点通视的所有点的集合
    can_not_seeregion = []
    for i in region:
        if agent.map.can_see(single_pos, i, 0) == False:
            can_not_seeregion.append(i)
    return can_not_seeregion


def infantry_defence_infer_coord(agent, obj_id, defense_cod):
    """
    袁铎
    :param defense_cod:
    :param agent:
    :param obj_id:
    :return: move_destination
    """
    # 没考虑为空的情况
    bop = agent.get_bop(obj_id)  # 重型战车的算子信息
    refer_defence_pos = None
    if defense_cod:  # 当传入防御点位的时候，防守区域是当前点和它的邻域
        refer_region = agent.map.get_neighbors(defense_cod)
        refer_region.append(defense_cod)
        refer_defence_pos = defense_cod
    else:  # 没有传入防御坐标，默认防御是夺控点
        refer_region = []  # 目标夺控点以及周围点位的点集
        distance = 65535
        for i in agent.city_coord:
            xx = True
            if agent.map.get_distance(bop['cur_hex'], i) < distance:  # 选取最近的不是其他步兵防御的夺控点作为目标防御点
                if agent.infantrt_defend_city:
                    if i in agent.infantrt_defend_city.values():
                        xx = False;
                if xx == True:
                    distance = agent.map.get_distance(bop['cur_hex'], i)
                    refer_defence_pos = i  # 目标夺控点
        if not refer_defence_pos:  # 如果多空点都被选择了，就随机选取一个
            refer_defence_pos = random.choice(agent.city_coord)
        refer_region.append(refer_defence_pos)
        single_city_nei = agent.map.get_neighbors(refer_defence_pos)  # 某个夺控点出现在其他的夺控点邻域会出现重复数据，可以用list（set（））解决
        refer_region += single_city_nei


    direction = get_direction(refer_defence_pos, bop['cur_hex'])
    direction_down = (direction + 1) % 6  #
    direction_up = (direction - 1) % 6

    _10_region = get_sector(refer_defence_pos,10,direction)# 以10为半径的半圆
    _10_region += get_sector(refer_defence_pos,10,direction_down)
    _10_region += get_sector(refer_defence_pos, 10, direction_up)

    _10_region = set(_10_region)

    #_10_region = agent.map.get_grid_distance(refer_defence_pos, 0, 10)  # 以10为半径的圆形
    in_cover_region = agent.map.get_grid_in_cover(_10_region)  # 在圆形中是隐蔽地形的
    without_road_in_cover_region = []
    for i in in_cover_region:
        if agent.map.get_road_type(i) == 0:
            without_road_in_cover_region.append(i)  # 在隐蔽地形中没有公路的

    _10_region_set = set(_10_region)
    without_road_in_cover_region_set = set(without_road_in_cover_region)

    candidate_region_set = _10_region_set - without_road_in_cover_region_set  # 除了没有公路的隐蔽点位的集合
    candidate_region = list(candidate_region_set)

    can_see_num_list = []  # 每个候选点与几个目标夺控点以及周围点位不通视
    for i in candidate_region:
        num = 0
        for j in refer_region:
            if agent.map.can_see(i, j, 0) == False:
                num += 1
        can_see_num_list.append(num)

    distance_target_candidate_list = []  # 目标点位和候选点位的距离
    for i in candidate_region:
        distance_target_candidate_list.append(agent.map.get_distance(i, refer_defence_pos))

    distance_candidate_home_list = []  # 候选点位和出发点位的距离
    for i in candidate_region:
        distance_candidate_home_list.append(agent.map.get_distance(i, bop['cur_hex']))

    max1 = max(can_see_num_list)
    max2 = max(distance_target_candidate_list)
    max3 = max(distance_candidate_home_list)

    weight_list = [0] * len(candidate_region)  # 权重存放列表
    for i in range(0, len(candidate_region) - 1):
        weight_list[i] += can_see_num_list[i] / max1
        weight_list[i] -= distance_target_candidate_list[i] / max2
        weight_list[i] -= distance_candidate_home_list[i] / max3

    car_tar_pos = candidate_region[weight_list.index(max(weight_list))]

    distance_target_final_tar_list = []  # 保存目标点位和周围点位 与 战车点位 的距离的集合
    for i in refer_region:
        distance_target_final_tar_list.append(agent.map.get_distance(i, car_tar_pos))

    if refer_region[distance_target_final_tar_list.index(
        min(distance_target_final_tar_list))]:
        return refer_defence_pos, refer_region[distance_target_final_tar_list.index(
        min(distance_target_final_tar_list))], car_tar_pos  # 返回 距离下车点位最近的一个点位作为防御点位 以及 下车点位
    else:
        return refer_defence_pos, refer_defence_pos, car_tar_pos


def infantry_defence_infer_coord_without_car(agent, obj_id, defense_cod):
    """
    袁铎
    :param defense_cod:
    :param agent:
    :param obj_id:
    :return: move_destination
    """
    # 此函数对应步兵距离夺控点很近不发送求情直接下车后再次被分配新任务重新进行位置推理的情况
    bop = agent.get_bop(obj_id)  # 步兵的算子信息
    refer_defence_pos = None
    if defense_cod:  # 当传入防御点位的时候，防守区域是当前点和它的邻域
        refer_region = agent.map.get_neighbors(defense_cod)
        refer_region.append(defense_cod)
        refer_defence_pos = defense_cod
    else:  # 没有传入防御坐标，默认防御是夺控点
        refer_region = []  # 目标夺控点以及周围点位的点集
        distance = 65535
        for i in agent.city_coord:
            xx = True
            if agent.map.get_distance(bop['cur_hex'], i) < distance:  # 选取最近的不是其他步兵防御的夺控点作为目标防御点
                if agent.infantrt_defend_city:
                    if i in agent.infantrt_defend_city.values():
                        xx = False;
                if xx == True:
                    distance = agent.map.get_distance(bop['cur_hex'], i)
                    refer_defence_pos = i  # 目标夺控点
        if not refer_defence_pos:  # 如果多空点都被选择了，就随机选取一个
            refer_defence_pos = random.choice(agent.city_coord)
        refer_region.append(refer_defence_pos)
        single_city_nei = agent.map.get_neighbors(refer_defence_pos)  # 某个夺控点出现在其他的夺控点邻域会出现重复数据，可以用list（set（））解决
        single_city_nei_with_cover = agent.map.get_grid_in_cover(single_city_nei)  # 在夺控点周围有隐蔽地形的点位
        single_city_nei_with_cover_list = list(single_city_nei_with_cover)
        distance = []
        for i in single_city_nei_with_cover_list:  # 计算隐蔽地形和当前步兵的距离
            distance.append(agent.map.get_distance(bop['cur_hex'], i))
        if single_city_nei_with_cover_list[distance.index(min(distance))]:
            return refer_defence_pos, single_city_nei_with_cover_list[distance.index(min(distance))], None
        else:
            return refer_defence_pos, refer_defence_pos, None


def Tank_defense_pos(agent, obj_id, defense_scope):
    """
        吴欣娟 2022/12/29
        推理坦克防御位置
        :param agent:
        :param obj_id:
        :param defense_scope:
        :return: defense_pos
    """
    bop = agent.get_bop(obj_id)
    new_area = []
    defense_scope_standby = []
    cover_pos = []
    pos_ability = {}
    if defense_scope:
        closest_hex = get_closest_hex(bop['cur_hex'], defense_scope)
        if closest_hex != bop['cur_hex']:
            area = agent.map.get_grid_distance(closest_hex, 7, 10)
            direction = get_direction(closest_hex, bop['cur_hex'])
            for pos in area:
                if get_direction(closest_hex, pos) == direction or get_direction(closest_hex, pos) == direction + 1 or \
                        get_direction(closest_hex, pos) == direction - 1:
                    new_area.append(pos)
            for pos in new_area:
                pos_ability.update({pos: weighted_average(agent, obj_id, pos, defense_scope)})

            def set_rank(a_dict):
                a_short_list = sorted(a_dict.items(), key=lambda x: x[1], reverse=True)
                a_short_dict = {}
                for n, s in a_short_list:
                    a_short_dict[n] = s
                return a_short_dict

            pos_ability_new = set_rank(pos_ability)
            i = 0
            for pos, ability in pos_ability_new.items():
                if i < 6:
                    defense_scope_standby.append(pos)
                    i += 1
            for pos in defense_scope_standby:
                if agent.map_data[pos // 100][pos % 100]['cond'] == 1 or \
                        agent.map_data[pos // 100][pos % 100]['cond'] == 2:
                    cover_pos.append(pos)
            if cover_pos:
                defense_pos = random.choice(cover_pos)
            else:
                defense_pos = random.choice(defense_scope_standby)
        else:
            defense_pos = bop['cur_hex']
    else:
        defense_pos = bop['cur_hex']
    return defense_pos


def weighted_average(agent, obj_id, standby_pos, defense_scope):
    """
           吴欣娟 2022/12/29
           计算备选防御点位的效能
           :param agent:
           :param obj_id:
           :param standby_pos:
           :param defense_scope:
           :return:
    """
    bop = agent.get_bop(obj_id)
    fire_coverage_standby = {}
    fire_coverage = []
    can_see = []
    neighbors = agent.map.get_neighbors(standby_pos)
    for neighbor in neighbors:
        fire_coverage_standby.update({neighbor: []})
        for pos in defense_scope:
            if agent.map.get_distance(neighbor, pos) < 10:
                fire_coverage_standby[neighbor].append(pos)
    for neighbor, coverage in fire_coverage_standby.items():
        fire_coverage = list(set(fire_coverage + coverage))
    support_shoot_ability = len(fire_coverage) / len(defense_scope)
    distance_ability = agent.map.get_distance(bop['cur_hex'], standby_pos)
    for pos in defense_scope:
        if agent.map.can_see(pos, standby_pos):
            can_see.append(pos)
    can_see_ability = len(can_see) / len(defense_scope)
    return support_shoot_ability * 0.4 + distance_ability * 0.1 + can_see_ability * 0.5


def infer_tank_attack_pos(agent, obj_id, region, target_pos):  # 缺少是否需要修改进攻点位
    """
    王炬江 2022/12/20
    坦克攻击点位推理
    :param agent: 对应的ai类
    :param obj_id:坦克的id值
    :param region: 需要进攻的区域
    :param target_pos: 传入的进攻中心
    :return:move_destination 推理出坦克的机动目标
    """
    bop = agent.get_bop(obj_id)
    if target_pos:
        refer_center = target_pos
    else:
        refer_center = agent.city_center
    hypotenuse = agent.map.get_distance(bop["cur_hex"], refer_center)
    if hypotenuse == 0:  # 三角形相似求出距离4格的圆心
        return
    row0, col0 = divmod(bop["cur_hex"], 100)
    row1, col1 = divmod(refer_center, 100)
    right_angle_side0 = abs(row0 - row1)
    right_angle_side1 = abs(col0 - col1)
    row18_len = int(4 * (right_angle_side0 / hypotenuse)) + 1
    col18_len = int(4 * (right_angle_side1 / hypotenuse)) + 1
    if row0 > row1 and col0 > col1:  # 4个象限的坐标调整
        move_destination_center = (row1 + row18_len) * 100 + col1 + col18_len
    elif row0 > row1 and col0 < col1:
        move_destination_center = (row1 + row18_len) * 100 + col1 - col18_len
    elif row0 < row1 and col0 < col1:
        move_destination_center = (row1 - row18_len) * 100 + col1 - col18_len
    else:
        move_destination_center = (row1 - row18_len) * 100 + col1 + col18_len
    # move_destination_center 可能是无效点超过地图的点
    move_destination_region0 = agent.map.get_grid_distance(move_destination_center, 0, 6)
    poss_attack_level = []
    move_destination_region = []
    for i in move_destination_region0:
        num1 = see_sum1(agent, i, region, obj_id)
        if num1 > 0:
            move_destination_region.append(i)
            poss_attack_level.append(num1)
    if not poss_attack_level:  # 没有可以通视点需要下达新的作战任务还是按照某种规则移动到一个点位？
        return
    max_see = max(poss_attack_level)  # 对通视的数量进行归一化
    attack_average0 = [i / max_see for i in poss_attack_level]
    attack_average1 = [agent.map.get_distance(i, bop["cur_hex"]) for i in move_destination_region]
    max_distance0 = max(attack_average1)  # 对距离当前的坐标距离归一化
    attack_average1 = [i / max_distance0 for i in attack_average1]
    attack_average2 = [1 if agent.map.is_in_cover(i) else 0 for i in move_destination_region]
    attack_average = [attack_average0[i] * 0.3 + attack_average1[i] * (-0.2) + attack_average2[i] * 0.5
                      for i in range(len(attack_average0))]  # 加权平均，即最后筛选的标准
    move_destinations = []
    max_see_average0 = max(attack_average)  # 极端情况attack_average不足三个时就是重复添加点
    index0 = attack_average.index(max_see_average0)
    attack_average[index0] = 0
    move_destination0 = move_destination_region[index0]
    move_destinations.append(move_destination0)
    max_see_average1 = max(attack_average)
    index1 = attack_average.index(max_see_average1)
    attack_average[index1] = 0
    move_destination1 = move_destination_region[index1]
    move_destinations.append(move_destination1)
    max_see_average2 = max(attack_average)
    index2 = attack_average.index(max_see_average2)
    move_destination2 = move_destination_region[index2]
    move_destinations.append(move_destination2)
    move_destination = random.choice(move_destinations)  # 采用随机，即等可能输出
    return move_destination


def see_sum1(agent, single, region, obj_id):  # "一个点对一个区域按照车辆通视计算攻击水平"
    bop = agent.get_bop(obj_id)
    tmp_bop0 = deepcopy(bop)  # 深拷贝防止数据的更改
    tmp_bop1 = deepcopy(bop)  # 有一个遗留问题通视的判断会以bop当时的状态判断比如掩蔽的影响
    attack_nei = [single]
    attack_nei += agent.map.get_neighbors(single)
    num = 0
    for i in region:
        tmp_bop0['cur_hex'] = attack_nei[0]
        tmp_bop1['cur_hex'] = i
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
            continue
        tmp_bop0['cur_hex'] = attack_nei[1]
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
            continue
        tmp_bop0['cur_hex'] = attack_nei[2]
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
            continue
        tmp_bop0['cur_hex'] = attack_nei[3]
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
            continue
        tmp_bop0['cur_hex'] = attack_nei[4]
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
            continue
        tmp_bop0['cur_hex'] = attack_nei[5]
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
            continue
        tmp_bop0['cur_hex'] = attack_nei[-1]
        if agent.map.check_2bop_see(tmp_bop0, tmp_bop1, 0):
            num += 1
    return num


def ifv_infer_attack_pos(agent, obj_id, region, target_pos):  # 缺少是否需要修改进攻点位
    """
    王炬江 2022/12/31
    重型战车攻击点位推理
    :param agent: 对应的ai类
    :param obj_id:战车的id值
    :param region: 需要进攻的区域
    :param target_pos: 传入的进攻中心
    :return:move_destination 推理出战车的机动目标
    """
    bop = agent.get_bop(obj_id)
    if target_pos:
        refer_center = target_pos
    else:
        refer_center = agent.city_center
    hypotenuse = agent.map.get_distance(bop["cur_hex"], refer_center)
    if hypotenuse == 0:  # 三角形相似求出距离4或者5格的圆心
        return
    row0, col0 = divmod(bop["cur_hex"], 100)
    row1, col1 = divmod(refer_center, 100)
    right_angle_side0 = abs(row0 - row1)
    right_angle_side1 = abs(col0 - col1)
    if 54 in bop["carry_weapon_ids"]:  # 小号直瞄炮射程13 偏移5半径8其余偏移4半径6
        row18_len = int(5 * (right_angle_side0 / hypotenuse)) + 1
        col18_len = int(5 * (right_angle_side1 / hypotenuse)) + 1
    else:
        row18_len = int(4 * (right_angle_side0 / hypotenuse)) + 1
        col18_len = int(4 * (right_angle_side1 / hypotenuse)) + 1
    if row0 > row1 and col0 > col1:  # 4个象限的坐标调整
        move_destination_center = (row1 + row18_len) * 100 + col1 + col18_len
    elif row0 > row1 and col0 < col1:
        move_destination_center = (row1 + row18_len) * 100 + col1 - col18_len
    elif row0 < row1 and col0 < col1:
        move_destination_center = (row1 - row18_len) * 100 + col1 - col18_len
    else:
        move_destination_center = (row1 - row18_len) * 100 + col1 + col18_len
    # move_destination_center 可能是无效点超过地图的点
    if 54 in bop["carry_weapon_ids"]:  # 小号直瞄炮射程13 偏移5半径8其余偏移4半径6
        move_destination_region0 = agent.map.get_grid_distance(move_destination_center, 0, 8)
    else:
        move_destination_region0 = agent.map.get_grid_distance(move_destination_center, 0, 6)
    poss_attack_level = []
    move_destination_region = []
    for i in move_destination_region0:
        num1 = see_sum(agent, i, region, obj_id)
        if num1 > 0:
            move_destination_region.append(i)
            poss_attack_level.append(num1)
    if not poss_attack_level:  # 没有可以通视点需要下达新的作战任务还是按照某种规则移动到一个点位？
        return
    max_see = max(poss_attack_level)  # 对通视的数量进行归一化
    attack_average0 = [i / max_see for i in poss_attack_level]
    attack_average1 = [agent.map.get_distance(i, bop["cur_hex"]) for i in move_destination_region]
    max_distance0 = max(attack_average1)  # 对距离当前的坐标距离归一化
    attack_average1 = [i / max_distance0 for i in attack_average1]
    attack_average2 = [1 if agent.map.is_in_cover(i) else 0 for i in move_destination_region]
    attack_average3 = [agent.map.get_distance(i, refer_center) for i in move_destination_region]
    max_distance11 = max(attack_average3)  # 对距离进攻目标中心距离归一化
    attack_average3 = [i / max_distance11 for i in attack_average3]
    attack_average = [attack_average0[i] * 0.1 + attack_average1[i] * (-0.2) + attack_average2[i] * 0.4 +
                      attack_average3[i] * 0.3 for i in range(len(attack_average0))]  # 加权平均，即最后筛选的标准
    move_destinations = []
    max_see_average0 = max(attack_average)  # 极端情况attack_average不足三个时就是重复添加点
    index0 = attack_average.index(max_see_average0)
    attack_average[index0] = 0
    move_destination0 = move_destination_region[index0]
    move_destinations.append(move_destination0)
    max_see_average1 = max(attack_average)
    index1 = attack_average.index(max_see_average1)
    attack_average[index1] = 0
    move_destination1 = move_destination_region[index1]
    move_destinations.append(move_destination1)
    max_see_average2 = max(attack_average)
    index2 = attack_average.index(max_see_average2)
    move_destination2 = move_destination_region[index2]
    move_destinations.append(move_destination2)
    move_destination = random.choice(move_destinations)  # 采用随机，即等可能输出
    return move_destination


def IFV_defense_pos(agent, obj_id, defense_scope):
    """
    2023-3-16 吴欣娟
    战车防御位置推理
    """
    area = []
    others_pos = []
    cover_pos = []
    no_cover_pos = []
    cover_pos_distance = {}
    cover_pos_standby = []
    no_cover_pos_distance = {}
    no_cover_pos_standby = []
    bop = agent.get_bop(obj_id)
    for id, pos in agent.IFV_defense_pos.items():
        if pos:
            others_pos.append(pos)
    for operator in agent.observation['operators']:
        if operator['color'] == agent.color:
            others_pos.append(operator['cur_hex'])
    if defense_scope:
        my_direction = get_direction(agent.city_center, agent.operator_center)
        # my_direction_set = [my_direction - 1, my_direction, my_direction + 1]
        my_direction_set = [my_direction]
        area_standby = agent.map.get_grid_distance(agent.city_center, 17, 22)
        for pos in others_pos:
            if pos in area_standby:
                area_standby.remove(pos)
        for pos in area_standby:
            if (get_direction(agent.city_center, pos) in my_direction_set) and (
                    agent.map.get_distance(pos, get_farrest_hex(pos, defense_scope)) < 20):
                area.append(pos)
        for pos in area:
            if agent.map_data[pos // 100][pos % 100]['cond'] == 1 or agent.map_data[pos // 100][pos % 100]['cond'] == 2:
                cover_pos.append(pos)
            else:
                no_cover_pos.append(pos)

        def set_rank_down(a_dict):
            a_short_list = sorted(a_dict.items(), key=lambda x: x[1], reverse=True)
            a_short_dict = {}
            for n, s in a_short_list:
                a_short_dict[n] = s
            return a_short_dict

        def set_rank_up(a_dict):
            a_short_list = sorted(a_dict.items(), key=lambda x: x[1], reverse=False)
            a_short_dict = {}
            for n, s in a_short_list:
                a_short_dict[n] = s
            return a_short_dict

        if cover_pos:
            for pos in cover_pos:
                cover_pos_distance.update({pos: agent.map.get_distance(pos, bop['cur_hex'])})
            cover_pos_rank = set_rank_up(cover_pos_distance)
            for i, (pos, ability) in enumerate(cover_pos_rank.items()):
                cover_pos_standby.append(pos)
                if i == 4:
                    break
            cover_pos_standby_distance = [agent.map.get_distance(pos, get_closest_hex(pos, defense_scope)) for pos in
                                          cover_pos_standby]
            defense_pos = cover_pos_standby[cover_pos_standby_distance.index(max(cover_pos_standby_distance))]
        elif no_cover_pos:
            for pos in cover_pos:
                no_cover_pos_distance.update({pos: get_closest_hex(pos, defense_scope)})
            no_cover_pos_rank = set_rank_down(cover_pos_distance)
            for i, (pos, ability) in enumerate(no_cover_pos_rank.items()):
                no_cover_pos_standby.append(pos)
                if i == 4:
                    break
            no_cover_pos_standby_distance = [agent.map.get_distance(pos, bop['cur_hex']) for pos in cover_pos_standby]
            defense_pos = cover_pos_standby[no_cover_pos_standby_distance.index(min(no_cover_pos_standby_distance))]
        else:
            defense_pos = bop['cur_hex']
    else:
        defense_pos = bop['cur_hex']
    return defense_pos


def disappeared_enemy_diffusion(agent, last_hex, radius):
    result = {}
    assign_weight_pos = set()
    for cur_radius in range(radius):
        if cur_radius == 0:
            result[last_hex] = 1  # 没有扩散或者半径是1的时候，圆心的概率是1
        else:
            assign_weight_pos = agent.map.get_grid_distance(last_hex, cur_radius - 1, cur_radius - 1)
            weight = {}
            for i in assign_weight_pos:  # 获取所有分配权重的坐标，分配前的权重
                weight[i] = result[i]
            for i in assign_weight_pos:
                result[i] = 0.4 * weight[i]  # 以0.4的概率保持原地不动
                single_assign_pos = agent.map.get_neighbors(i)
                for v in single_assign_pos:  # 本轮参与扩散的坐标的权重在这里计算
                    if v in assign_weight_pos:
                        result[i] = result[i] + 0.1 * weight[v]
                        # single_assign_pos.append(i)
                for j in single_assign_pos:
                    if j in assign_weight_pos:  # 扩散的坐标的权重不在这里计算
                        continue
                    if j not in result.keys():
                        result[j] = 0
                    result[j] = result[j] + 0.1 * weight[i]  # 以0.1的概率往邻域扩散
    return result


def disappeared_enemy_diffusion1(agent, last_hex, last_diffusion, radius):
    last_diffusion_standby = copy.deepcopy(last_diffusion)
    if radius == 0:
        last_diffusion[last_hex] = 1  # 没有扩散或者半径是0的时候，圆心的概率是1
    else:
        outermost_poss = agent.map.get_grid_distance(last_hex, radius, radius)
        if len(outermost_poss) != 6 * radius:
            return  # 扩散到地图外侧的情况，不继续更新扩散模型
        secondary_outermost_poss = agent.map.get_grid_distance(last_hex, radius - 1, radius - 1)
        if radius > 1:
            other_poss = agent.map.get_grid_distance(last_hex, 0, radius - 2)
        else:
            other_poss = set()
        for i in outermost_poss:  # 最外圈点的概率计算
            if i not in last_diffusion.keys():  # 在属性中初始化该点
                last_diffusion[i] = 0
                last_diffusion_standby[i] = 0
            i_nei = agent.map.get_neighbors(i)
            for j in i_nei:  # 找出可以扩散到该点的坐标
                if j in secondary_outermost_poss:
                    last_diffusion[i] += last_diffusion[j] * 0.1
        for i in secondary_outermost_poss:
            cur_value = last_diffusion_standby[i] * 0.4
            add_value = 0
            i_nei = agent.map.get_neighbors(i)
            for j in i_nei:
                add_value += last_diffusion_standby[j] * 0.1
            last_diffusion[i] = cur_value + add_value
        for i in other_poss:
            cur_value = last_diffusion_standby[i] * 0.4
            add_value = 0
            i_nei = agent.map.get_neighbors(i)
            for j in i_nei:
                add_value += last_diffusion_standby[j] * 0.1
            last_diffusion[i] = cur_value + add_value
    return last_diffusion


def disappeared_enemy_diffusion2(agent, last_hex, last_diffusion, radius):
    """
    遍历上一次扩散模型中所有的概率非零点。先取出下一次仍然在当前坐标的概率，在将遍历的每一个点的概率分配给它的邻域中点
    """
    outermost_poss = agent.map.get_grid_distance(last_hex, radius, radius)
    if radius == 0:
        last_diffusion[last_hex] = 1  # 没有扩散或者半径是0的时候，圆心的概率是1
        return last_diffusion
    if len(outermost_poss) != 6 * radius:
        return  # 扩散到地图外侧的情况，不继续更新扩散模型
    last_diffusion_standby = copy.deepcopy(last_diffusion)
    for i in last_diffusion:
        last_diffusion[i] = 0.4 * last_diffusion[i]  # 每一个有概率的点保持不动的部分的概率
    for i in last_diffusion_standby:
        if last_diffusion[i] == 0:
            continue  # 概率为0的点没有转移给邻域点概率
        i_nei = agent.map.get_neighbors(i)
        for j in i_nei:  # 将i中的点的概率分配给j
            if last_diffusion.get(j) is None:  # j没有在扩散模型的时候
                last_diffusion[j] = 0.1 * last_diffusion_standby[i]
            else:
                last_diffusion[j] += 0.1 * last_diffusion_standby[i]
    return last_diffusion


def CruiseMissle_patrol1(agent, CruiseMissle_region, cur_hex, refer_work_center):
    best_pos = cur_hex  # 最后输出的点
    not_type = [5, 6, 7, 8]
    main_battlefield_enemy_diffusion = set()
    main_battlefield_enemy_diffusion_probability = []
    lost_time = []  # 对应每个消失点，记录这个点在扩散模型中丢失的最久的时间
    # if len(agent.situation.disappeared_enemy_diffusion) > 2:
        # print("hjj")
    for i in agent.situation.disappeared_enemy_diffusion:  # 取出扩散模型中所有有的点，概率为0的也会在
        if agent.situation.disappeared_enemy_diffusion[i]['sub_type'] in not_type:
            continue  # 不用去寻找消失的无人机
        main_battlefield_enemy_diffusion = main_battlefield_enemy_diffusion.union \
            (set(agent.situation.disappeared_enemy_diffusion[i]['diffusion'].keys()))
    main_battlefield_enemy_diffusion = main_battlefield_enemy_diffusion.intersection(agent.situation.main_battlefield)
    main_battlefield_enemy_diffusion_list = list(main_battlefield_enemy_diffusion)
    for i in main_battlefield_enemy_diffusion_list:
        probability = 0  # 遍历所有属于主战场区域的扩散模型的点，并且计算出对应点的所有消失敌人敌人总的概率和
        time = 0
        for j in agent.situation.disappeared_enemy_diffusion:
            if agent.situation.disappeared_enemy_diffusion[j]['sub_type'] in not_type:
                continue  # 不用去寻找消失的无人机
            if agent.situation.disappeared_enemy_diffusion[j]["diffusion"].get(i, None):  # 概率是0的也是False
                probability += agent.situation.disappeared_enemy_diffusion[j]["diffusion"][i]
                if time < agent.situation.disappeared_enemy_diffusion[j]['radius']:
                    time = agent.situation.disappeared_enemy_diffusion[j]['radius']
        main_battlefield_enemy_diffusion_probability.append(probability)
        lost_time.append(time)
    if not main_battlefield_enemy_diffusion_list:  # 主战场区域中没有扩散模型中点
        best_pos = random.choice(agent.situation.patrol_standby)
        return best_pos
    if max(main_battlefield_enemy_diffusion_probability) == 0:  # 主战场区域虽然有点，但是是已经确定没有敌人的点
        best_pos = random.choice(agent.situation.patrol_standby)
        return best_pos
    max_probability = max(main_battlefield_enemy_diffusion_probability)
    average1 = [i / max_probability for i in main_battlefield_enemy_diffusion_probability]
    average2 = [agent.map.get_distance(i, cur_hex) for i in main_battlefield_enemy_diffusion_list]
    max_distance1 = max(average2)  # 对距离巡飞弹当前的距离进行归一化
    average2 = [i / max_distance1 for i in average2]
    average3 = [agent.map.get_distance(i, refer_work_center) for i in main_battlefield_enemy_diffusion_list]
    max_distance2 = max(average3)  # 对距离分配的巡飞弹工作中心距离进行归一化
    average3 = [i / max_distance2 for i in average3]
    max_time = max(lost_time)
    average4 = [i / max_time for i in lost_time]
    average = [average1[i] * 0.3 + average2[i] * (-0.2) + average3[i] * (-0.2) + average4[i] * 0.3
               for i in range(len(average1))]  # 加权平均，即最后筛选的标准
    b = average.index(max(average))
    best_pos = main_battlefield_enemy_diffusion_list[b]
    return best_pos


def RV_infer_detect_pos(agent, obj_id, refer_center):
    bop = agent.get_bop(obj_id)
    detect_region = list(agent.map.get_grid_distance(refer_center, 0, 5))
    hypotenuse = agent.map.get_distance(bop["cur_hex"], refer_center)
    if hypotenuse == 0:  # 三角形相似求出距离4格的圆心
        return
    row0, col0 = divmod(bop["cur_hex"], 100)
    row1, col1 = divmod(refer_center, 100)
    right_angle_side0 = abs(row0 - row1)
    right_angle_side1 = abs(col0 - col1)
    row18_len = int(27 * (right_angle_side0 / hypotenuse)) + 1
    col18_len = int(27 * (right_angle_side1 / hypotenuse)) + 1
    if row0 > row1 and col0 > col1:  # 4个象限的坐标调整
        move_destination_center = (row1 + row18_len) * 100 + col1 + col18_len
    elif row0 > row1 and col0 < col1:
        move_destination_center = (row1 + row18_len) * 100 + col1 - col18_len
    elif row0 < row1 and col0 < col1:
        move_destination_center = (row1 - row18_len) * 100 + col1 - col18_len
    else:
        move_destination_center = (row1 - row18_len) * 100 + col1 + col18_len
    # move_destination_center 可能是无效点超过地图的点
    move_destination_region0 = agent.map.get_grid_distance(move_destination_center, 0, 6)
    poss_observe_level = []
    move_destination_region = []
    for i in move_destination_region0:
        num1 = see_sum(agent, i, detect_region, obj_id)
        if num1 > 0:
            move_destination_region.append(i)
            poss_observe_level.append(num1)
    if not poss_observe_level:  # 没有可以通视点需要下达新的作战任务还是按照某种规则移动到一个点位？
        return
    max_see = max(poss_observe_level)  # 对通视的数量进行归一化
    detect_average0 = [i / max_see for i in poss_observe_level]
    detect_average1 = [1 if agent.map.is_in_cover(i) else 0 for i in move_destination_region]
    detect_average = [detect_average0[i] * 0.7 + detect_average1[i] * 0.3
                      for i in range(len(detect_average0))]  # 加权平均，即最后筛选的标准
    move_destinations = []
    max_see_average0 = max(detect_average)  # 极端情况detect_average不足三个时就是重复添加点
    index0 = detect_average.index(max_see_average0)
    detect_average[index0] = 0
    move_destination0 = move_destination_region[index0]
    move_destinations.append(move_destination0)
    max_see_average1 = max(detect_average)
    index1 = detect_average.index(max_see_average1)
    detect_average[index1] = 0
    move_destination1 = move_destination_region[index1]
    move_destinations.append(move_destination1)
    max_see_average2 = max(detect_average)
    index2 = detect_average.index(max_see_average2)
    move_destination2 = move_destination_region[index2]
    move_destinations.append(move_destination2)
    detect_pos = random.choice(move_destinations)  # 采用随机，即等可能输出
    return detect_pos


def Helicopter_infer_attack_pos(agent, obj_id, refer_center):
    bop = agent.get_bop(obj_id)
    hypotenuse = agent.map.get_distance(bop["cur_hex"], refer_center)
    if hypotenuse == 0:  # 三角形相似
        return
    row0, col0 = divmod(bop["cur_hex"], 100)
    row1, col1 = divmod(refer_center, 100)
    right_angle_side0 = abs(row0 - row1)
    right_angle_side1 = abs(col0 - col1)
    if 73 in bop["carry_weapon_ids"] and bop["remain_bullet_nums"][100] > 0:
        # 有重型导弹的时候，找到距离攻击目标17格的点位，没有重型导弹时找到距离5格的点位
        row18_len = int(17 * (right_angle_side0 / hypotenuse)) + 1
        col18_len = int(17 * (right_angle_side1 / hypotenuse)) + 1
    else:
        row18_len = int(5 * (right_angle_side0 / hypotenuse)) + 1
        col18_len = int(5 * (right_angle_side1 / hypotenuse)) + 1
    if row0 > row1 and col0 > col1:  # 4个象限的坐标调整
        move_destination_center = (row1 + row18_len) * 100 + col1 + col18_len
    elif row0 > row1 and col0 < col1:
        move_destination_center = (row1 + row18_len) * 100 + col1 - col18_len
    elif row0 < row1 and col0 < col1:
        move_destination_center = (row1 - row18_len) * 100 + col1 - col18_len
    else:
        move_destination_center = (row1 - row18_len) * 100 + col1 + col18_len
    # move_destination_center 可能是无效点超过地图的点
    return move_destination_center

def uv_infer_coord0(agent, obj_id, attack_cod):
    bop = agent.get_bop(obj_id)
    # 有进攻目标的时候进攻的区域是进攻目标及其邻域。没有的时候是夺控点区域
    if attack_cod:
        refer_center = attack_cod
        region = agent.map.get_neighbors(attack_cod)
        region.append(attack_cod)
    else:
        refer_center = agent.city_center
        region = agent.city_neighbor_3
    hypotenuse = agent.map.get_distance(bop["cur_hex"], refer_center)
    if hypotenuse == 0:  # 三角形相似求出距离4或者5格的圆心
        return
    row0, col0 = divmod(bop["cur_hex"], 100)
    row1, col1 = divmod(refer_center, 100)
    right_angle_side0 = abs(row0 - row1)
    right_angle_side1 = abs(col0 - col1)
    # 偏移5半径6
    row18_len = int(5 * (right_angle_side0 / hypotenuse)) + 1
    col18_len = int(5 * (right_angle_side1 / hypotenuse)) + 1
    if row0 > row1 and col0 > col1:  # 4个象限的坐标调整
        move_destination_center = (row1 + row18_len) * 100 + col1 + col18_len
    elif row0 > row1 and col0 < col1:
        move_destination_center = (row1 + row18_len) * 100 + col1 - col18_len
    elif row0 < row1 and col0 < col1:
        move_destination_center = (row1 - row18_len) * 100 + col1 - col18_len
    else:
        move_destination_center = (row1 - row18_len) * 100 + col1 + col18_len
    # move_destination_center 可能是无效点超过地图的点
    move_destination_region0 = agent.map.get_grid_distance(move_destination_center, 0, 6)
    poss_attack_level = []
    move_destination_region = []
    for i in move_destination_region0:
        num1 = see_sum(agent, i, region, obj_id)
        if num1 > 0:
            move_destination_region.append(i)
            poss_attack_level.append(num1)
    if not poss_attack_level:  # 没有可以通视点需要下达新的作战任务还是按照某种规则移动到一个点位？
        return  # TODO 出现这种情况的时候会前往夺控点！！！（重型战车也是如此）
    max_see = max(poss_attack_level)  # 对通视的数量进行归一化
    attack_average0 = [i / max_see for i in poss_attack_level]
    attack_average1 = [agent.map.get_distance(i, bop["cur_hex"]) for i in move_destination_region]
    max_distance0 = max(attack_average1)  # 对距离当前的坐标距离归一化
    attack_average1 = [i / max_distance0 for i in attack_average1]
    attack_average2 = [1 if agent.map.is_in_cover(i) else 0 for i in move_destination_region]
    attack_average3 = [agent.map.get_distance(i, refer_center) for i in move_destination_region]
    max_distance11 = max(attack_average3)  # 对距离进攻目标中心距离归一化
    attack_average3 = [i / max_distance11 for i in attack_average3]
    attack_average = [attack_average0[i] * 0.2 + attack_average1[i] * (-0.2) + attack_average2[i] * 0.3 +
                      attack_average3[i] * 0.3 for i in range(len(attack_average0))]  # 加权平均，即最后筛选的标准
    move_destinations = []
    max_see_average0 = max(attack_average)  # 极端情况attack_average不足三个时就是重复添加点
    index0 = attack_average.index(max_see_average0)
    attack_average[index0] = 0
    move_destination0 = move_destination_region[index0]
    move_destinations.append(move_destination0)
    max_see_average1 = max(attack_average)
    index1 = attack_average.index(max_see_average1)
    attack_average[index1] = 0
    move_destination1 = move_destination_region[index1]
    move_destinations.append(move_destination1)
    max_see_average2 = max(attack_average)
    index2 = attack_average.index(max_see_average2)
    move_destination2 = move_destination_region[index2]
    move_destinations.append(move_destination2)
    move_destination = random.choice(move_destinations)  # 采用随机，即等可能输出
    return move_destination